package test.xinhe.perf.gatling.test.ck

import java.text.SimpleDateFormat
import java.time.{LocalDate, LocalDateTime}
import java.util.Date

import io.gatling.core.Predef._
import io.gatling.core.session
import org.apache.commons.vfs2.provider.UriParser
import org.xinhe.perf.gatling.sql.Predef.sql
import org.xinhe.perf.gatling.sql.db.ConnectionPool
import org.xinhe.perf.gatling.util.SftpUtils
import test.xinhe.perf.gatling.test.common.RemoteShellTool
import org.xinhe.perf.gatling.sql.Predef.{sql, _}

import scala.util.Random


/**
 * @ClassName: QueryJDBC
 * @Date: 2021-4-9
 * @author: sunxinhe
 * @Version: 1.0
 * @Description:
 * 写入测试：单用户单条写入
 *
 */
class QueryJDBC extends Simulation {

  class Host(var ip: String, var port: Int, var userName: String, var password: String)

  val host = new Host("172.20.32.119", 22, "root", "rootroot")
  //  val host = new Host("192.168.12.103", 22, "root", "rootroot")

  var monitorKey = new SimpleDateFormat("yyyyMMdd").format(new Date()) + "/" + queryName() + "/" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())

  val conn = ConnectionPool.connection

  val sqlConfig = sql.connection(conn)


  //TODO 试试这个feeder https://gatling.io/docs/2.2/session/feeder/
  val randomIdFeeder = Array(
    Map("plateColor" -> 0, "plateNo" -> "浙A27865", "plateNoLike" -> "浙A278%"),
    Map("plateColor" -> 1, "plateNo" -> "浙A67491", "plateNoLike" -> "浙A674%"),
    Map("plateColor" -> 0, "plateNo" -> "浙A98411", "plateNoLike" -> "浙A984%"),
    Map("plateColor" -> 1, "plateNo" -> "浙A47823", "plateNoLike" -> "浙A478%"),
    Map("plateColor" -> 2, "plateNo" -> "浙A58672", "plateNoLike" -> "浙A586%"),
    Map("plateColor" -> 2, "plateNo" -> "浙A41277", "plateNoLike" -> "浙A412%"),
    Map("plateColor" -> 1, "plateNo" -> "浙A30556", "plateNoLike" -> "浙A305%"),
    Map("plateColor" -> 0, "plateNo" -> "浙A30924", "plateNoLike" -> "浙A309%"),
    Map("plateColor" -> 2, "plateNo" -> "浙A47823", "plateNoLike" -> "浙A478%"),
    Map("plateColor" -> 1, "plateNo" -> "浙A58672", "plateNoLike" -> "浙A586%"),
    Map("plateColor" -> 2, "plateNo" -> "浙A30556", "plateNoLike" -> "浙A305%"),
    Map("plateColor" -> 1, "plateNo" -> "浙A41277", "plateNoLike" -> "浙A412%"),
    Map("plateColor" -> 2, "plateNo" -> "浙A67491", "plateNoLike" -> "浙A674%"),
    Map("plateColor" -> 1, "plateNo" -> "浙A27865", "plateNoLike" -> "浙A278%"),
    Map("plateColor" -> 0, "plateNo" -> "浙A67491", "plateNoLike" -> "浙A674%"),
    Map("plateColor" -> 0, "plateNo" -> "浙A30556", "plateNoLike" -> "浙A305%"),
    Map("plateColor" -> 0, "plateNo" -> "浙A47823", "plateNoLike" -> "浙A478%"),
    Map("plateColor" -> 1, "plateNo" -> "浙A98411", "plateNoLike" -> "浙A984%"),
    Map("plateColor" -> 1, "plateNo" -> "浙A30924", "plateNoLike" -> "浙A309%"),
    Map("plateColor" -> 0, "plateNo" -> "浙A41277", "plateNoLike" -> "浙A412%"),
    Map("plateColor" -> 2, "plateNo" -> "浙A98411", "plateNoLike" -> "浙A984%"),
    Map("plateColor" -> 0, "plateNo" -> "浙A58672", "plateNoLike" -> "浙A586%"),
    Map("plateColor" -> 2, "plateNo" -> "浙A30924", "plateNoLike" -> "浙A309%"),
    Map("plateColor" -> 2, "plateNo" -> "浙A27865", "plateNoLike" -> "浙A278%")
  )

  val scn =
    scenario("query-like").repeat(repeatTimes) {
      feed(randomIdFeeder.random).exec(sql(queryName()).selectQuery(sqlQuery()))
    }

  setUp(scn.inject(atOnceUsers(userAmount())))
    .protocols(sqlConfig)


  before(monitorStart())
  after(monitorStop())


  //region 压测配置
  def userAmount(): Int = 1

  def batchSize(): Int = 100

  def repeatTimes: Int = 5000 / userAmount()

  //endregion

  //region 压测SQL
  def sqlQuery(): String = {
    //TODO 生成 Insert sql
    var querySql: String = "SELECT\n\t" +
      "id,\n\t" +
      "plate_type,\n\t" +
      "plate_no,\n\t" +
      "speed,\n\t" +
      "appear_time,\n\t" +
      "mark_time,\n\t" +
      "device_id,\n\t" +
      "vehicle_image,\n\t" +
      "scene_image,\n\t" +
      "vehicle_color,\n\t" +
      "area_code,\n\t" +
      "line_no,\n\t" +
      "pass_time,\n\t" +
      "plate_color,\n\t" +
      "plate_describe,\n\t" +
      "disappear_time,\n\t" +
      "insert_time,\n\t" +
      "vehicle_class\n" +
      "FROM\n\t" +
      "default.ck_perf_vehicle_1u1000r\n" +
      "where\n\t" +
      "plate_color = '${plateColor}'\n\t" +
      "and plate_no like '${plateNoLike}'\n" +
      "limit " + batchSize() + ";"

    println(querySql)

    querySql.toString
  }


  //endregion


  //region 监控工具
  def monitorStart(): Unit = {
    println("monitorStart")
    // 定义工作路径
    val localShellPath = "/data/gatling/monitor/shell/"
    val localDataPath = "/data/gatling/monitor/data/" + monitorKey + "/"
    val remoteShellPath = "/data/gatling/monitor/shell/" + monitorKey + "/"
    val remoteDataPath = "/data/gatling/monitor/data/" + monitorKey + "/"
    val rms = new RemoteShellTool(host.ip, host.port, host.userName, host.password)


    // 上传监控脚本
    println("上传监控脚本")
    println(rms.exec("mkdir -p " + remoteShellPath))
    println(rms.exec("cat << 'EOF' >> " + remoteShellPath + "monitor.sh\n\n" +
      "#!/bin/bash\n" +
      "#获取当前shell脚本路径\n" +
      "base_dir=$(cd \"$(dirname $0)\";pwd)\n" +
      "cd $base_dir\n" +
      "pwd\n" +
      "start_date=`date \"+%Y%m%d\"`\n" +
      "echo $start_date\n\n" +
      "monitor_log_path=$base_dir\"/\"$start_date\"-monitor.log\"\n\n" +
      "nohup tsar --live --cpu --mem --traffic --load --io -s user,sys,wait,util,free,used,buff,cach,total,load1,runq,plit,bytin,bytout,rqsize,rarqsz,warqsz,await  -i 1 >> $monitor_log_path & echo $! > monitor.pid\n" +
      ""))


    //    SftpUtils.upload(host.ip, host.userName, host.password, localShellPath + "monitor.sh", remoteShellPath + "monitor.sh")

    // 启动监控脚本并记录pid到文件
    println("启动监控任务")
    println(rms.exec("chmod +x " + remoteShellPath + "monitor.sh"))
    println(rms.exec("sh " + remoteShellPath + "monitor.sh"))
    println(rms.exec("cat " + remoteShellPath + "monitor.pid"))
    println(rms.exec("ps aux | grep tsar"))

  }

  def monitorStop(): Unit = {
    println("monitorStop")
    // 定义工作路径
    val localShellPath = "/data/gatling/monitor/shell/"
    val localDataPath = "/data/gatling/monitor/data/" + monitorKey + "/"
    val remoteShellPath = "/data/gatling/monitor/shell/" + monitorKey + "/"
    val remoteDataPath = "/data/gatling/monitor/data/" + monitorKey + "/"

    // 按照文件记录的pid kill监控任务
    val rms = new RemoteShellTool(host.ip, host.port, host.userName, host.password)
    println("停止监控任务")
    println(rms.exec("mkdir -p " + remoteShellPath))
    println(rms.exec("kill -9 `cat " + remoteShellPath + "monitor.pid`"))


    //TODO 下载监控数据
  }

  //endregion


  //region 数据模拟工具
  def queryName(): String = {
    "query_jdbc_".concat(userAmount().toString).concat("_").concat(batchSize().toString).concat("_")
  }

  def randomId: String = randomCode(8)

  def randomPassTime: String = LocalDateTime.now().toString

  def randomCode: String = {
    randomCode(6)
  }

  def randomCode(size: Int): String = {
    var code = ""
    val chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
    for (i <- 1 to size) {
      code += chars charAt (Random.nextInt(chars.length))
    }
    code
  }

  def randomInt(start: Int, end: Int): Int = {
    Random.nextInt(end).%(end - start).+(start)
  }

  def randomInt(n: Int): Int = {
    Random.nextInt(n)
  }

  //endregion
}
